home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 1843 / 1843.xpi / content / firebug / reps.js < prev    next >
Text File  |  2010-01-15  |  54KB  |  1,889 lines

  1. /* See license.txt for terms of usage */
  2.  
  3. var FirebugReps = FBL.ns(function() { with (FBL) {
  4.  
  5. // ************************************************************************************************
  6. // Constants
  7.  
  8. const Cc = Components.classes;
  9. const Ci = Components.interfaces;
  10. const jsdIStackFrame = Ci.jsdIStackFrame;
  11. const jsdIScript = Ci.jsdIScript;
  12.  
  13. const fbs = Cc["@joehewitt.com/firebug;1"].getService().wrappedJSObject;
  14.  
  15. // ************************************************************************************************
  16. // Common Tags
  17.  
  18. var OBJECTBOX = this.OBJECTBOX =
  19.     SPAN({"class": "objectBox objectBox-$className", role : "presentation"});
  20.  
  21. var OBJECTBLOCK = this.OBJECTBLOCK =
  22.     DIV({"class": "objectBox objectBox-$className focusRow subLogRow", role : "listitem"});
  23.  
  24. var OBJECTLINK = this.OBJECTLINK =
  25.     A({
  26.         "class": "objectLink objectLink-$className a11yFocus",
  27.         _repObject: "$object"
  28.     });
  29.  
  30. // ************************************************************************************************
  31.  
  32. this.Undefined = domplate(Firebug.Rep,
  33. {
  34.     tag: OBJECTBOX("undefined"),
  35.  
  36.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  37.  
  38.     className: "undefined",
  39.  
  40.     supportsObject: function(object, type)
  41.     {
  42.         return type == "undefined";
  43.     }
  44. });
  45.  
  46. // ************************************************************************************************
  47.  
  48. this.Null = domplate(Firebug.Rep,
  49. {
  50.     tag: OBJECTBOX("null"),
  51.  
  52.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  53.  
  54.     className: "null",
  55.  
  56.     supportsObject: function(object, type)
  57.     {
  58.         return object == null;
  59.     }
  60. });
  61.  
  62. // ************************************************************************************************
  63.  
  64. this.Nada = domplate(Firebug.Rep,
  65. {
  66.     tag: SPAN(""),
  67.  
  68.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  69.  
  70.     className: "nada"
  71. });
  72.  
  73. // ************************************************************************************************
  74.  
  75. this.Number = domplate(Firebug.Rep,
  76. {
  77.     tag: OBJECTBOX("$object"),
  78.  
  79.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  80.  
  81.     className: "number",
  82.  
  83.     supportsObject: function(object, type)
  84.     {
  85.         return type == "boolean" || type == "number";
  86.     }
  87. });
  88.  
  89. // ************************************************************************************************
  90.  
  91. this.String = domplate(Firebug.Rep,
  92. {
  93.     tag: OBJECTBOX(""$object""),
  94.  
  95.     shortTag: OBJECTBOX(""$object|cropMultipleLines""),
  96.  
  97.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  98.  
  99.     className: "string",
  100.  
  101.     supportsObject: function(object, type)
  102.     {
  103.         return type == "string";
  104.     }
  105. });
  106.  
  107. // ************************************************************************************************
  108.  
  109. this.XML = domplate(Firebug.Rep,
  110. {
  111.     tag: OBJECTBOX("$object|asString"),
  112.  
  113.     shortTag: OBJECTBOX("$object|asShortString"),
  114.  
  115.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  116.  
  117.     className: "xml",
  118.  
  119.     supportsObject: function(object, type)
  120.     {
  121.         return type == "xml";
  122.     },
  123.  
  124.     asString: function(object)
  125.     {
  126.         return object.toXMLString();
  127.     },
  128.  
  129.     asShortString: function(object)
  130.     {
  131.         return cropMultipleLines(this.asString(object));
  132.     },
  133. });
  134.  
  135. // ************************************************************************************************
  136.  
  137. this.Text = domplate(Firebug.Rep,
  138. {
  139.     tag: OBJECTBOX("$object"),
  140.  
  141.     shortTag: OBJECTBOX("$object|cropMultipleLines"),
  142.  
  143.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  144.  
  145.     className: "text"
  146. });
  147.  
  148. // ************************************************************************************************
  149.  
  150. this.Caption = domplate(Firebug.Rep,
  151. {
  152.     tag: SPAN({"class": "caption"}, "$object")
  153. });
  154.  
  155. // ************************************************************************************************
  156.  
  157. this.Warning = domplate(Firebug.Rep,
  158. {
  159.     tag: DIV({"class": "warning focusRow", role : 'listitem'}, "$object|STR")
  160. });
  161.  
  162. // ************************************************************************************************
  163.  
  164. this.Func = domplate(Firebug.Rep,
  165. {
  166.     tag:
  167.         OBJECTLINK("$object|summarizeFunction"),
  168.  
  169.     summarizeFunction: function(fn)
  170.     {
  171.         var fnRegex = /function ([^(]+\([^)]*\)) \{/;
  172.         var fnText = safeToString(fn);
  173.  
  174.         var m = fnRegex.exec(fnText);
  175.         return m ? m[1] : "function()";
  176.     },
  177.  
  178.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  179.  
  180.     copySource: function(fn)
  181.     {
  182.         copyToClipboard(safeToString(fn));
  183.     },
  184.  
  185.     monitor: function(fn, script, monitored)
  186.     {
  187.         if (monitored)
  188.             Firebug.Debugger.unmonitorScript(fn, script, "monitor");
  189.         else
  190.             Firebug.Debugger.monitorScript(fn, script, "monitor");
  191.     },
  192.  
  193.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  194.  
  195.     className: "function",
  196.  
  197.     supportsObject: function(object, type)
  198.     {
  199.         return type == "function";
  200.     },
  201.  
  202.     inspectObject: function(fn, context)
  203.     {
  204.         var sourceLink = findSourceForFunction(fn, context);
  205.         if (sourceLink)
  206.             Firebug.chrome.select(sourceLink);
  207.     },
  208.  
  209.     getTooltip: function(fn, context)
  210.     {
  211.         /*  XXjjb I think this is very expensive...
  212.         var script = findScriptForFunctionInContext(context, fn);
  213.         if (script)
  214.             return $STRF("Line", [normalizeURL(script.fileName), script.baseLineNumber]);
  215.         else
  216.          */
  217.             if (fn.toString)
  218.                 return fn.toString();
  219.     },
  220.  
  221.     getTitle: function(fn, context)
  222.     {
  223.         var name = fn.name ? fn.name : "function";
  224.         return name + "()";
  225.     },
  226.  
  227.     getContextMenuItems: function(fn, target, context, script)
  228.     {
  229.         if (!script)
  230.             script = findScriptForFunctionInContext(context, fn);
  231.         if (!script)
  232.             return;
  233.  
  234.         var scriptInfo = Firebug.SourceFile.getSourceFileAndLineByScript(context, script);
  235.         var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false;
  236.  
  237.         var name = script ? getFunctionName(script, context) : fn.name;
  238.         return [
  239.             {label: "CopySource", command: bindFixed(this.copySource, this, fn) },
  240.             "-",
  241.             {label: $STRF("ShowCallsInConsole", [name]), nol10n: true,
  242.              type: "checkbox", checked: monitored,
  243.              command: bindFixed(this.monitor, this, fn, script, monitored) }
  244.         ];
  245.     }
  246. });
  247.  
  248. // ************************************************************************************************
  249.  
  250. this.jsdScript = domplate(Firebug.Rep,
  251. {
  252.     copySource: function(script)
  253.     {
  254.         var fn = unwrapIValue(script.functionObject);
  255.         return FirebugReps.Func.copySource(fn);
  256.     },
  257.  
  258.     monitor: function(fn, script, monitored)
  259.     {
  260.         fn = unwrapIValue(script.functionObject);
  261.         return FirebugReps.Func.monitor(fn, script, monitored);
  262.     },
  263.  
  264.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  265.  
  266.     className: "jsdScript",
  267.     inspectable: false,
  268.  
  269.     supportsObject: function(object, type)
  270.     {
  271.         return object instanceof jsdIScript;
  272.     },
  273.  
  274.     inspectObject: function(script, context)
  275.     {
  276.         var sourceLink = getSourceLinkForScript(script, context);
  277.         if (sourceLink)
  278.             Firebug.chrome.select(sourceLink);
  279.     },
  280.  
  281.     getRealObject: function(script, context)
  282.     {
  283.         return script;
  284.     },
  285.  
  286.     getTooltip: function(script)
  287.     {
  288.         return $STRF("jsdIScript", [script.tag]);
  289.     },
  290.  
  291.     getTitle: function(script, context)
  292.     {
  293.         var fn = unwrapIValue(script.functionObject);
  294.         return FirebugReps.Func.getTitle(fn, context);
  295.     },
  296.  
  297.     getContextMenuItems: function(script, target, context)
  298.     {
  299.         var fn = unwrapIValue(script.functionObject);
  300.  
  301.         var scriptInfo = Firebug.SourceFile.getSourceFileAndLineByScript(context, script);
  302.            var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false;
  303.  
  304.         var name = getFunctionName(script, context);
  305.  
  306.         return [
  307.             {label: "CopySource", command: bindFixed(this.copySource, this, script) },
  308.             "-",
  309.             {label: $STRF("ShowCallsInConsole", [name]), nol10n: true,
  310.              type: "checkbox", checked: monitored,
  311.              command: bindFixed(this.monitor, this, fn, script, monitored) }
  312.         ];
  313.     }
  314. });
  315.  
  316. //************************************************************************************************
  317.  
  318. this.Obj = domplate(Firebug.Rep,
  319. {
  320.     tag:
  321.         OBJECTLINK(
  322.             SPAN({"class": "objectTitle"}, "$object|getTitle "),
  323.             SPAN({"class": "objectLeftBrace", role: "presentation"}, "{"),
  324.             FOR("prop", "$object|shortPropIterator",
  325.                 " $prop.name",
  326.                 SPAN({"class": "objectEqual", role: "presentation"}, "$prop.equal"),
  327.                 TAG("$prop.tag", {object: "$prop.object"}),
  328.                 SPAN({"class": "objectComma", role: "presentation"}, "$prop.delim")
  329.             ),
  330.             SPAN({"class": "objectRightBrace"}, "}")
  331.         ),
  332.  
  333.     shortTag:
  334.         OBJECTLINK(
  335.             SPAN({"class": "objectTitle"}, "$object|getTitle "),
  336.             SPAN({"class": "objectLeftBrace", role: "presentation"}, "{"),
  337.             FOR("prop", "$object|shortPropIterator",
  338.                 " $prop.name",
  339.                 SPAN({"class": "objectEqual", role: "presentation"}, "$prop.equal"),
  340.                 TAG("$prop.tag", {object: "$prop.object"}),
  341.                 SPAN({"class": "objectComma", role: "presentation"}, "$prop.delim")
  342.             ),
  343.             SPAN({"class": "objectRightBrace"}, "}")
  344.         ),
  345.  
  346.     titleTag:
  347.         SPAN({"class": "objectTitle"}, "$object|getTitle"),
  348.  
  349.     longPropIterator: function (object)
  350.     {
  351.         return this.propIterator(object,100);
  352.     },
  353.  
  354.     shortPropIterator: function (object)
  355.     {
  356.         return this.propIterator(object,1);
  357.     },
  358.  
  359.     propIterator: function (object, max)
  360.     {
  361.         max = max || 3;
  362.         if (!object)
  363.             return [];
  364.  
  365.         var props = [];
  366.         var len = 0, count = 0;
  367.  
  368.         try
  369.         {
  370.             for (var name in object)
  371.             {
  372.                 var value;
  373.                 try
  374.                 {
  375.                     value = object[name];
  376.                 }
  377.                 catch (exc)
  378.                 {
  379.                     continue;
  380.                 }
  381.  
  382.                 var t = typeof(value);
  383.                 if (t == "boolean" || t == "number" || (t == "string" && value)
  384.                     || (t == "object" && value && value.toString))
  385.                 {
  386.                     var rep = Firebug.getRep(value);
  387.                     var tag = rep.shortTag || rep.tag;
  388.                     if (t == "object")
  389.                     {
  390.                         value = rep.getTitle(value);
  391.                         tag = rep.titleTag;
  392.                     }
  393.                     count++;
  394.                     if (count <= max)
  395.                         props.push({tag: tag, name: name, object: value, equal: "=", delim: ", "});
  396.                     else
  397.                         break;
  398.                 }
  399.             }
  400.             if (count > max)
  401.             {
  402.                 props[Math.max(1,max-1)] = {
  403.                     object: "more...", //xxxHonza localization
  404.                     tag: FirebugReps.Caption.tag,
  405.                     name: "",
  406.                     equal:"",
  407.                     delim:""
  408.                 };
  409.             }
  410.             else if (props.length > 0)
  411.             {
  412.                 props[props.length-1].delim = '';
  413.             }
  414.         }
  415.         catch (exc)
  416.         {
  417.             // Sometimes we get exceptions when trying to read from certain objects, like
  418.             // StorageList, but don't let that gum up the works
  419.             // XXXjjb also History.previous fails because object is a web-page object which does not have
  420.             // permission to read the history
  421.         }
  422.         return props;
  423.     },
  424.  
  425.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  426.  
  427.     className: "object",
  428.  
  429.     supportsObject: function(object, type)
  430.     {
  431.         return true;
  432.     }
  433. });
  434.  
  435.  
  436. // ************************************************************************************************
  437.  
  438. this.Arr = domplate(Firebug.Rep,
  439. {
  440.     tag:
  441.         OBJECTBOX({_repObject: "$object",
  442.             $hasTwisty: "$object|hasSpecialProperties",
  443.             onclick: "$onToggleProperties"},
  444.             SPAN({"class": "arrayLeftBracket", role: "presentation"}, "["),
  445.             FOR("item", "$object|longArrayIterator",
  446.                 TAG("$item.tag", {object: "$item.object"}),
  447.                 SPAN({"class": "arrayComma", role: "presentation"}, "$item.delim")
  448.             ),
  449.             SPAN({"class": "arrayRightBracket", role: "presentation"}, "]"),
  450.             SPAN({"class": "arrayProperties", role: "group"})
  451.         ),
  452.  
  453.     shortTag:
  454.         OBJECTBOX({_repObject: "$object",
  455.             $hasTwisty: "$object|hasSpecialProperties",
  456.             onclick: "$onToggleProperties"},
  457.             SPAN({"class": "arrayLeftBracket", role: "presentation"}, "["),
  458.             FOR("item", "$object|shortArrayIterator",
  459.                 TAG("$item.tag", {object: "$item.object"}),
  460.                 SPAN({"class": "arrayComma", role: "presentation"}, "$item.delim")
  461.             ),
  462.             SPAN({"class": "arrayRightBracket"}, "]"),
  463.             SPAN({"class": "arrayProperties", role: "group"})
  464.         ),
  465.  
  466.     longArrayIterator: function(array)
  467.     {
  468.        return this.arrayIterator(array,300);
  469.     },
  470.  
  471.     shortArrayIterator: function(array)
  472.     {
  473.        return this.arrayIterator(array,3);
  474.     },
  475.  
  476.     arrayIterator: function(array, max)
  477.     {
  478.         var items = [];
  479.         for (var i = 0; i < array.length && i <= max; ++i)
  480.         {
  481.             var value = array[i];
  482.             var rep = Firebug.getRep(value);
  483.             var tag = rep.shortTag || rep.tag;
  484.             var delim = (i == array.length-1 ? "" : ", ");
  485.  
  486.             items.push({object: value, tag: tag, delim: delim});
  487.         }
  488.  
  489.         if (array.length > max + 1)
  490.         {
  491.             items[max] = {
  492.                 object: (array.length-max) + " more...", //xxxHonza localization
  493.                 tag: FirebugReps.Caption.tag,
  494.                 delim: ""
  495.             };
  496.         }
  497.  
  498.         return items;
  499.     },
  500.  
  501.     toggles: {},
  502.  
  503.     getItemIndex: function(child)
  504.     {
  505.         var arrayIndex = 0;
  506.         for (child = child.previousSibling; child; child = child.previousSibling)
  507.         {
  508.             if (child.repObject)
  509.                 ++arrayIndex;
  510.         }
  511.         return arrayIndex;
  512.     },
  513.  
  514.     hasSpecialProperties: function(array)
  515.     {
  516.         return (array.length != array.__count__) && hasProperties(array);
  517.     },
  518.  
  519.     onToggleProperties: function(event)
  520.     {
  521.         var target = event.originalTarget;
  522.         if (hasClass(target, "objectBox-array"))
  523.         {
  524.             toggleClass(target, "opened");
  525.  
  526.             var propBox = target.getElementsByClassName("arrayProperties").item(0);
  527.             if (hasClass(target, "opened"))
  528.                 Firebug.DOMPanel.DirTable.tag.replace(
  529.                     {object: target.repObject, toggles: this.toggles}, propBox);
  530.             else
  531.                 clearNode(propBox);
  532.         }
  533.     },
  534.  
  535.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  536.  
  537.     className: "array",
  538.  
  539.     supportsObject: function(object)
  540.     {
  541.         return this.isArray(object);
  542.     },
  543.  
  544.     // http://code.google.com/p/fbug/issues/detail?id=874
  545.     // BEGIN Yahoo BSD Source (modified here)  YAHOO.lang.isArray, YUI 2.2.2 June 2007
  546.     isArray: function(obj) {
  547.         try {
  548.             if (!obj)
  549.                 return false;
  550.             else if (obj instanceof Ci.nsIDOMHistory) // do this first to avoid security 1000 errors
  551.                 return false;
  552.             else if (obj instanceof StorageList) // do this first to avoid security 1000 errors
  553.                 return false;
  554.             else if (isFinite(obj.length) && typeof obj.splice === 'function')
  555.                 return true;
  556.             else if (isFinite(obj.length) && typeof obj.callee === 'function') // arguments
  557.                 return true;
  558.             else if (obj instanceof HTMLCollection)
  559.                 return true;
  560.             else if (obj instanceof NodeList)
  561.                 return true;
  562.             else
  563.                 return false;
  564.         }
  565.         catch(exc)
  566.         {
  567.         }
  568.  
  569.         return false;
  570.     },
  571.     // END Yahoo BSD SOURCE See license below.
  572.  
  573.     getTitle: function(object, context)
  574.     {
  575.         return "[" + object.length + "]";
  576.     }
  577. });
  578.  
  579. // ************************************************************************************************
  580.  
  581. this.Property = domplate(Firebug.Rep,
  582. {
  583.     supportsObject: function(object)
  584.     {
  585.         return object instanceof Property;
  586.     },
  587.  
  588.     getRealObject: function(prop, context)
  589.     {
  590.         return prop.object[prop.name];
  591.     },
  592.  
  593.     getTitle: function(prop, context)
  594.     {
  595.         return prop.name;
  596.     }
  597. });
  598.  
  599. // ************************************************************************************************
  600.  
  601. this.NetFile = domplate(this.Obj,
  602. {
  603.     supportsObject: function(object)
  604.     {
  605.         return object instanceof Firebug.NetFile;
  606.     },
  607.  
  608.     browseObject: function(file, context)
  609.     {
  610.         openNewTab(file.href);
  611.         return true;
  612.     },
  613.  
  614.     getRealObject: function(file, context)
  615.     {
  616.         return null;
  617.     }
  618. });
  619.  
  620. // ************************************************************************************************
  621.  
  622. this.Except = domplate(Firebug.Rep,
  623. {
  624.     tag:
  625.         OBJECTBOX({_repObject: "$object"}, "$object.message"),
  626.  
  627.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  628.  
  629.     className: "exception",
  630.  
  631.     supportsObject: function(object)
  632.     {
  633.         return object instanceof ErrorCopy;
  634.     }
  635. });
  636.  
  637.  
  638. // ************************************************************************************************
  639.  
  640. this.Element = domplate(Firebug.Rep,
  641. {
  642.     tag:
  643.         OBJECTLINK(
  644.             "<",
  645.             SPAN({"class": "nodeTag"}, "$object.localName|toLowerCase"),
  646.             FOR("attr", "$object|attrIterator",
  647.                 " $attr.localName="", SPAN({"class": "nodeValue"}, "$attr.nodeValue"), """
  648.             ),
  649.             ">"
  650.          ),
  651.  
  652.     shortTag:
  653.         OBJECTLINK(
  654.             SPAN({"class": "$object|getVisible"},
  655.                 SPAN({"class": "selectorTag"}, "$object|getSelectorTag"),
  656.                 SPAN({"class": "selectorId"}, "$object|getSelectorId"),
  657.                 SPAN({"class": "selectorClass"}, "$object|getSelectorClass"),
  658.                 SPAN({"class": "selectorValue"}, "$object|getValue")
  659.             )
  660.          ),
  661.  
  662.     getVisible: function(elt)
  663.     {
  664.         return isVisible(elt) ? "" : "selectorHidden";
  665.     },
  666.  
  667.     getSelectorTag: function(elt)
  668.     {
  669.         return elt.localName.toLowerCase();
  670.     },
  671.  
  672.     getSelectorId: function(elt)
  673.     {
  674.         return elt.id ? ("#" + elt.id) : "";
  675.     },
  676.  
  677.     getSelectorClass: function(elt)
  678.     {
  679.         return elt.getAttribute("class")
  680.             ? ("." + elt.getAttribute("class").split(" ")[0])
  681.             : "";
  682.     },
  683.  
  684.     getValue: function(elt)
  685.     {
  686.         var value;
  687.  
  688.         if (elt instanceof HTMLImageElement)
  689.             value = getFileName(elt.getAttribute("src"));
  690.         else if (elt instanceof HTMLAnchorElement)
  691.             value = getFileName(elt.getAttribute("href"));
  692.         else if (elt instanceof HTMLInputElement)
  693.             value = elt.getAttribute("value");
  694.         else if (elt instanceof HTMLFormElement)
  695.             value = getFileName(elt.getAttribute("action"));
  696.         else if (elt instanceof HTMLScriptElement)
  697.             value = getFileName(elt.getAttribute("src"));
  698.  
  699.         return value ? " " + cropMultipleLines(value, 20) : "";
  700.      },
  701.  
  702.      attrIterator: function(elt)
  703.      {
  704.          var attrs = [];
  705.          var idAttr, classAttr;
  706.          if (elt.attributes)
  707.          {
  708.              for (var i = 0; i < elt.attributes.length; ++i)
  709.              {
  710.                  var attr = elt.attributes[i];
  711.                  if (attr.localName.indexOf("-moz-math") != -1)
  712.                      continue;
  713.                  if (attr.localName.indexOf("firebug-") != -1)
  714.                      continue;
  715.                  else if (attr.localName == "id")
  716.                      idAttr = attr;
  717.                  else if (attr.localName == "class")
  718.                      classAttr = attr;
  719.                  else
  720.                      attrs.push(attr);
  721.              }
  722.          }
  723.          if (classAttr)
  724.             attrs.splice(0, 0, classAttr);
  725.         if (idAttr)
  726.            attrs.splice(0, 0, idAttr);
  727.          return attrs;
  728.      },
  729.  
  730.      shortAttrIterator: function(elt)
  731.      {
  732.          var attrs = [];
  733.          if (elt.attributes)
  734.          {
  735.              for (var i = 0; i < elt.attributes.length; ++i)
  736.              {
  737.                  var attr = elt.attributes[i];
  738.                  if (attr.localName == "id" || attr.localName == "class")
  739.                      attrs.push(attr);
  740.              }
  741.          }
  742.  
  743.          return attrs;
  744.      },
  745.  
  746.      getHidden: function(elt)
  747.      {
  748.          return isVisible(elt) ? "" : "nodeHidden";
  749.      },
  750.  
  751.      getXPath: function(elt)
  752.      {
  753.          return getElementTreeXPath(elt);
  754.      },
  755.  
  756.      getNodeTextGroups: function(element)
  757.      {
  758.          var text =  element.textContent;
  759.          if (!Firebug.showFullTextNodes)
  760.          {
  761.              text=cropString(text,50);
  762.          }
  763.  
  764.          var escapeGroups=[];
  765.  
  766.          if (Firebug.showTextNodesWithWhitespace)
  767.              escapeGroups.push({
  768.                 'group': 'whitespace',
  769.                 'class': 'nodeWhiteSpace',
  770.                 'extra': {
  771.                     '\t': '_Tab',
  772.                     '\n': '_Para',
  773.                     ' ' : '_Space'
  774.                 }
  775.              });
  776.          if (Firebug.showTextNodesWithEntities)
  777.              escapeGroups.push({
  778.                  'group':'text',
  779.                  'class':'nodeTextEntity',
  780.                  'extra':{}
  781.              });
  782.  
  783.          if (escapeGroups.length)
  784.              return escapeGroupsForEntities(text, escapeGroups);
  785.          else
  786.              return [{str:text,'class':'',extra:''}];
  787.      },
  788.  
  789.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  790.  
  791.     copyHTML: function(elt)
  792.     {
  793.         var html = getElementHTML(elt);
  794.         copyToClipboard(html);
  795.     },
  796.  
  797.     copyInnerHTML: function(elt)
  798.     {
  799.         copyToClipboard(elt.innerHTML);
  800.     },
  801.  
  802.     copyXPath: function(elt)
  803.     {
  804.         var xpath = getElementXPath(elt);
  805.         copyToClipboard(xpath);
  806.     },
  807.  
  808.     persistor: function(context, xpath)
  809.     {
  810.         var elts = xpath
  811.             ? getElementsByXPath(context.window.document, xpath)
  812.             : null;
  813.  
  814.         return elts && elts.length ? elts[0] : null;
  815.     },
  816.  
  817.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  818.  
  819.     className: "element",
  820.  
  821.     supportsObject: function(object)
  822.     {
  823.         return object instanceof Element;
  824.     },
  825.  
  826.     browseObject: function(elt, context)
  827.     {
  828.         var tag = elt.localName.toLowerCase();
  829.         if (tag == "script")
  830.             openNewTab(elt.src);
  831.         else if (tag == "link")
  832.             openNewTab(elt.href);
  833.         else if (tag == "a")
  834.             openNewTab(elt.href);
  835.         else if (tag == "img")
  836.             openNewTab(elt.src);
  837.  
  838.         return true;
  839.     },
  840.  
  841.     persistObject: function(elt, context)
  842.     {
  843.         var xpath = getElementXPath(elt);
  844.  
  845.         return bind(this.persistor, top, xpath);
  846.     },
  847.  
  848.     getTitle: function(element, context)
  849.     {
  850.         return getElementCSSSelector(element);
  851.     },
  852.  
  853.     getTooltip: function(elt)
  854.     {
  855.         return this.getXPath(elt);
  856.     },
  857.  
  858.     getContextMenuItems: function(elt, target, context)
  859.     {
  860.         var monitored = areEventsMonitored(elt, null, context);
  861.         var CopyElement = "CopyHTML";
  862.         if (isElementSVG(elt))
  863.             CopyElement = "CopySVG";
  864.         if (isElementMathML(elt))
  865.             CopyElement = "CopyMathML";
  866.  
  867.         var items=[{label: CopyElement, command: bindFixed(this.copyHTML, this, elt)}];
  868.         if (!isElementSVG(elt) && !isElementMathML(elt))
  869.             items.push({label: "CopyInnerHTML", command: bindFixed(this.copyInnerHTML, this, elt) });
  870.  
  871.         return items.concat([
  872.             {label: "CopyXPath", command: bindFixed(this.copyXPath, this, elt) },
  873.             "-",
  874.             {label: "ShowEventsInConsole", type: "checkbox", checked: monitored,
  875.              command: bindFixed(toggleMonitorEvents, FBL, elt, null, monitored, context) },
  876.             "-",
  877.             {label: "ScrollIntoView", command: bindFixed(elt.scrollIntoView, elt) }
  878.         ]);
  879.     }
  880. });
  881.  
  882. // ************************************************************************************************
  883.  
  884. this.TextNode = domplate(Firebug.Rep,
  885. {
  886.     tag:
  887.         OBJECTLINK(
  888.             "<",
  889.             SPAN({"class": "nodeTag"}, "TextNode"),
  890.             " textContent="", SPAN({"class": "nodeValue"}, "$object.textContent|cropMultipleLines"), """,
  891.             ">"
  892.             ),
  893.  
  894.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  895.  
  896.     className: "textNode",
  897.  
  898.     inspectObject: function(node, context)
  899.     {
  900.         // Text nodes have two displays in HTML panel, inline and distinct
  901.         // node. We need to examine which case we are dealing with in order to
  902.         // select the proper object.
  903.         if (Firebug.HTMLLib.hasNoElementChildren(node.parentNode))
  904.         {
  905.             node = node.parentNode;
  906.         }
  907.  
  908.         Firebug.chrome.select(node, "html", "domSide");
  909.     },
  910.  
  911.     supportsObject: function(object)
  912.     {
  913.         return object instanceof Text;
  914.     },
  915.  
  916.     getTitle: function(win, context)
  917.     {
  918.         return "textNode";
  919.     }
  920. });
  921.  
  922. // ************************************************************************************************
  923.  
  924. this.Document = domplate(Firebug.Rep,
  925. {
  926.     tag:
  927.         OBJECTLINK("Document ", SPAN({"class": "objectPropValue"}, "$object|getLocation")),
  928.  
  929.     getLocation: function(doc)
  930.     {
  931.         return doc.location ? getFileName(doc.location.href) : "";
  932.     },
  933.  
  934.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  935.  
  936.     className: "object",
  937.  
  938.     supportsObject: function(object)
  939.     {
  940.         return object instanceof Document || object instanceof XMLDocument;
  941.     },
  942.  
  943.     browseObject: function(doc, context)
  944.     {
  945.         openNewTab(doc.location.href);
  946.         return true;
  947.     },
  948.  
  949.     persistObject: function(doc, context)
  950.     {
  951.         return this.persistor;
  952.     },
  953.  
  954.     persistor: function(context)
  955.     {
  956.         return context.window.document;
  957.     },
  958.  
  959.     getTitle: function(win, context)
  960.     {
  961.         return "document";
  962.     },
  963.  
  964.     getTooltip: function(doc)
  965.     {
  966.         return doc.location.href;
  967.     }
  968. });
  969.  
  970. // ************************************************************************************************
  971.  
  972. this.StyleSheet = domplate(Firebug.Rep,
  973. {
  974.     tag:
  975.         OBJECTLINK("StyleSheet ", SPAN({"class": "objectPropValue"}, "$object|getLocation")),
  976.  
  977.     getLocation: function(styleSheet)
  978.     {
  979.         return getFileName(styleSheet.href);
  980.     },
  981.  
  982.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  983.  
  984.     copyURL: function(styleSheet)
  985.     {
  986.         copyToClipboard(styleSheet.href);
  987.     },
  988.  
  989.     openInTab: function(styleSheet)
  990.     {
  991.         openNewTab(styleSheet.href);
  992.     },
  993.  
  994.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  995.  
  996.     className: "object",
  997.  
  998.     supportsObject: function(object)
  999.     {
  1000.         return object instanceof CSSStyleSheet;
  1001.     },
  1002.  
  1003.     browseObject: function(styleSheet, context)
  1004.     {
  1005.         openNewTab(styleSheet.href);
  1006.         return true;
  1007.     },
  1008.  
  1009.     persistObject: function(styleSheet, context)
  1010.     {
  1011.         return bind(this.persistor, top, styleSheet.href);
  1012.     },
  1013.  
  1014.     getTooltip: function(styleSheet)
  1015.     {
  1016.         return styleSheet.href;
  1017.     },
  1018.  
  1019.     getContextMenuItems: function(styleSheet, target, context)
  1020.     {
  1021.         return [
  1022.             {label: "CopyLocation", command: bindFixed(this.copyURL, this, styleSheet) },
  1023.             "-",
  1024.             {label: "OpenInTab", command: bindFixed(this.openInTab, this, styleSheet) }
  1025.         ];
  1026.     },
  1027.  
  1028.     persistor: function(context, href)
  1029.     {
  1030.         return getStyleSheetByHref(href, context);
  1031.     }
  1032. });
  1033.  
  1034. // ************************************************************************************************
  1035.  
  1036. this.Window = domplate(Firebug.Rep,
  1037. {
  1038.     tag:
  1039.         OBJECTLINK("Window ", SPAN({"class": "objectPropValue"}, "$object|getLocation")),
  1040.  
  1041.     getLocation: function(win)
  1042.     {
  1043.         try
  1044.         {
  1045.             return (win && win.location && !win.closed) ? getFileName(win.location.href) : "";
  1046.         }
  1047.         catch (exc)
  1048.         {
  1049.         }
  1050.     },
  1051.  
  1052.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1053.  
  1054.     className: "object",
  1055.  
  1056.     supportsObject: function(object)
  1057.     {
  1058.         return object instanceof Window;
  1059.     },
  1060.  
  1061.     browseObject: function(win, context)
  1062.     {
  1063.         openNewTab(win.location.href);
  1064.         return true;
  1065.     },
  1066.  
  1067.     persistObject: function(win, context)
  1068.     {
  1069.         return this.persistor;
  1070.     },
  1071.  
  1072.     persistor: function(context)
  1073.     {
  1074.         return context.window;
  1075.     },
  1076.  
  1077.     getTitle: function(win, context)
  1078.     {
  1079.         return "window";
  1080.     },
  1081.  
  1082.     getTooltip: function(win)
  1083.     {
  1084.         if (win && !win.closed)
  1085.             return win.location.href;
  1086.     }
  1087. });
  1088.  
  1089. // ************************************************************************************************
  1090.  
  1091. this.Event = domplate(Firebug.Rep,
  1092. {
  1093.     tag: TAG("$copyEventTag", {object: "$object|copyEvent"}),
  1094.  
  1095.     copyEventTag:
  1096.         OBJECTLINK("$object|summarizeEvent"),
  1097.  
  1098.     summarizeEvent: function(event)
  1099.     {
  1100.         var info = [event.type, ' '];
  1101.  
  1102.         var eventFamily = getEventFamily(event.type);
  1103.         if (eventFamily == "mouse")
  1104.             info.push("clientX=", event.clientX, ", clientY=", event.clientY);
  1105.         else if (eventFamily == "key")
  1106.             info.push("charCode=", event.charCode, ", keyCode=", event.keyCode);
  1107.  
  1108.         return info.join("");
  1109.     },
  1110.  
  1111.     copyEvent: function(event)
  1112.     {
  1113.         return new EventCopy(event);
  1114.     },
  1115.  
  1116.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1117.  
  1118.     className: "object",
  1119.  
  1120.     supportsObject: function(object)
  1121.     {
  1122.         return object instanceof Event || object instanceof EventCopy;
  1123.     },
  1124.  
  1125.     getTitle: function(event, context)
  1126.     {
  1127.         return "Event " + event.type;
  1128.     }
  1129. });
  1130.  
  1131. // ************************************************************************************************
  1132.  
  1133. this.SourceLink = domplate(Firebug.Rep,
  1134. {
  1135.     tag:
  1136.         OBJECTLINK(
  1137.             {$collapsed: "$object|hideSourceLink"},
  1138.             DIV("$object|getSourceLinkTitle"),
  1139.             DIV({$systemLink: "$object|isSystemLink"}, "$object|getSystemFlagTitle")),
  1140.  
  1141.     isSystemLink: function(sourceLink)
  1142.     {
  1143.         return sourceLink && isSystemURL(sourceLink.href);
  1144.     },
  1145.  
  1146.     hideSourceLink: function(sourceLink)
  1147.     {
  1148.         return sourceLink ? sourceLink.href.indexOf("XPCSafeJSObjectWrapper") != -1 : true;
  1149.     },
  1150.  
  1151.     getSourceLinkTitle: function(sourceLink)
  1152.     {
  1153.         if (!sourceLink)
  1154.             return "";
  1155.  
  1156.         try
  1157.         {
  1158.             var fileName = getFileName(sourceLink.href);
  1159.             fileName = decodeURIComponent(fileName);
  1160.             fileName = cropString(fileName, 17);
  1161.         }
  1162.         catch(exc)
  1163.         {
  1164.             fileName = sourceLink.href;
  1165.         }
  1166.         if (sourceLink.instance)
  1167.             return $STRF("InstanceLine", [fileName, sourceLink.instance+1, sourceLink.line]);
  1168.         else if (sourceLink.line)
  1169.             return $STRF("Line", [fileName, sourceLink.line]);
  1170.         else
  1171.             return fileName;
  1172.     },
  1173.  
  1174.     getSystemFlagTitle: function(sourceLink)
  1175.     {
  1176.         if (this.isSystemLink(sourceLink))
  1177.             return $STRF("SystemItem", [""]);
  1178.         else
  1179.             return "";
  1180.     },
  1181.  
  1182.     copyLink: function(sourceLink)
  1183.     {
  1184.         copyToClipboard(sourceLink.href);
  1185.     },
  1186.  
  1187.     openInTab: function(sourceLink)
  1188.     {
  1189.         openNewTab(sourceLink.href);
  1190.     },
  1191.  
  1192.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1193.  
  1194.     className: "sourceLink",
  1195.  
  1196.     supportsObject: function(object)
  1197.     {
  1198.         return object instanceof SourceLink;
  1199.     },
  1200.  
  1201.     getTooltip: function(sourceLink)
  1202.     {
  1203.         return decodeURI(sourceLink.href);
  1204.     },
  1205.  
  1206.     inspectObject: function(sourceLink, context)
  1207.     {
  1208.         if (sourceLink.type == "js")
  1209.         {
  1210.             var scriptFile = getSourceFileByHref(sourceLink.href, context);
  1211.             if (scriptFile)
  1212.                 return Firebug.chrome.select(sourceLink);
  1213.         }
  1214.         else if (sourceLink.type == "css")
  1215.         {
  1216.             // If an object is defined, treat it as the highest priority for
  1217.             // inspect actions
  1218.             if (sourceLink.object) {
  1219.                 Firebug.chrome.select(sourceLink.object);
  1220.                 return;
  1221.             }
  1222.  
  1223.             var stylesheet = getStyleSheetByHref(sourceLink.href, context);
  1224.             if (stylesheet)
  1225.             {
  1226.                 var ownerNode = stylesheet.ownerNode;
  1227.                 if (ownerNode)
  1228.                 {
  1229.                     Firebug.chrome.select(sourceLink, "html");
  1230.                     return;
  1231.                 }
  1232.  
  1233.                 var panel = context.getPanel("stylesheet");
  1234.                 if (panel && panel.getRuleByLine(stylesheet, sourceLink.line))
  1235.                     return Firebug.chrome.select(sourceLink);
  1236.             }
  1237.         }
  1238.         else if (sourceLink.type == "net")
  1239.         {
  1240.             return Firebug.chrome.select(sourceLink);
  1241.         }
  1242.  
  1243.         // Fallback is to just open the view-source window on the file
  1244.         viewSource(sourceLink.href, sourceLink.line);
  1245.     },
  1246.  
  1247.     browseObject: function(sourceLink, context)
  1248.     {
  1249.         openNewTab(sourceLink.href);
  1250.         return true;
  1251.     },
  1252.  
  1253.     getContextMenuItems: function(sourceLink, target, context)
  1254.     {
  1255.         return [
  1256.             {label: "CopyLocation", command: bindFixed(this.copyLink, this, sourceLink) },
  1257.             "-",
  1258.             {label: "OpenInTab", command: bindFixed(this.openInTab, this, sourceLink) }
  1259.         ];
  1260.     }
  1261. });
  1262.  
  1263. // ************************************************************************************************
  1264.  
  1265. this.SourceFile = domplate(this.SourceLink,
  1266. {
  1267.     tag:
  1268.         OBJECTLINK({$collapsed: "$object|hideSourceLink"}, "$object|getSourceLinkTitle"),
  1269.  
  1270.     persistor: function(context, href)
  1271.     {
  1272.         return getSourceFileByHref(href, context);
  1273.     },
  1274.  
  1275.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1276.  
  1277.     className: "sourceFile",
  1278.  
  1279.     supportsObject: function(object)
  1280.     {
  1281.         return object instanceof Firebug.SourceFile;
  1282.     },
  1283.  
  1284.     persistObject: function(sourceFile)
  1285.     {
  1286.         return bind(this.persistor, top, sourceFile.href);
  1287.     },
  1288.  
  1289.     browseObject: function(sourceLink, context)
  1290.     {
  1291.     },
  1292.  
  1293.     getTooltip: function(sourceFile)
  1294.     {
  1295.         return sourceFile.href;
  1296.     }
  1297. });
  1298.  
  1299. // ************************************************************************************************
  1300.  
  1301. this.StackFrame = domplate(Firebug.Rep,  // XXXjjb Since the repObject is fn the stack does not have correct line numbers
  1302. {
  1303.     tag:
  1304.         OBJECTBLOCK(
  1305.             A({"class": "objectLink a11yFocus", _repObject: "$object"}, "$object|getCallName"),
  1306.             SPAN("("),
  1307.             FOR("arg", "$object|argIterator",
  1308.                 TAG("$arg.tag", {object: "$arg.value"}),
  1309.                 SPAN({"class": "arrayComma"}, "$arg.delim")
  1310.             ),
  1311.             SPAN(")"),
  1312.             SPAN({"class": "objectLink-sourceLink objectLink a11yFocus",
  1313.                 _repObject: "$object|getSourceLink",
  1314.                 role: "link"},
  1315.                 "$object|getSourceLinkTitle")
  1316.         ),
  1317.  
  1318.     getCallName: function(frame)
  1319.     {
  1320.         if (frame.fn && frame.fn != "anonymous")
  1321.             return frame.fn;
  1322.         return getFunctionName(frame.script, frame.context, null, true);
  1323.     },
  1324.  
  1325.     getSourceLinkTitle: function(frame)
  1326.     {
  1327.         var fileName = cropString(getFileName(frame.href), 17);
  1328.         return $STRF("Line", [fileName, frame.line]);
  1329.     },
  1330.  
  1331.     argIterator: function(frame)
  1332.     {
  1333.         if (!frame.args)
  1334.             return [];
  1335.  
  1336.         var items = [];
  1337.  
  1338.         for (var i = 0; i < frame.args.length; ++i)
  1339.         {
  1340.             var arg = frame.args[i];
  1341.  
  1342.             if (!arg)
  1343.                 break;
  1344.  
  1345.             if (arg.value) // then we got these from jsd
  1346.             {
  1347.                 var rep = Firebug.getRep(arg.value);
  1348.                 var tag = rep.shortTag ? rep.shortTag : rep.tag;
  1349.  
  1350.                 var delim = (i == frame.args.length-1 ? "" : ", ");
  1351.  
  1352.                 items.push({name: arg.name, value: arg.value, tag: tag, delim: delim});
  1353.             }
  1354.             else  // eg from Error object
  1355.             {
  1356.                 var delim = (i == frame.args.length-1 ? "" : ", ");
  1357.                 var rep = Firebug.getRep(arg);
  1358.                 var tag = rep.shortTag ? rep.shortTag : rep.tag;
  1359.  
  1360.                 items.push({value: arg, tag: tag, delim: delim});
  1361.             }
  1362.         }
  1363.  
  1364.         return items;
  1365.     },
  1366.  
  1367.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1368.  
  1369.     className: "stackFrame",
  1370.  
  1371.     supportsObject: function(object)
  1372.     {
  1373.         return object instanceof StackFrame;
  1374.     },
  1375.  
  1376.     inspectObject: function(stackFrame, context)
  1377.     {
  1378.         Firebug.chrome.select(this.getSourceLink(stackFrame));
  1379.     },
  1380.  
  1381.     getTooltip: function(stackFrame, context)
  1382.     {
  1383.         return $STRF("Line", [stackFrame.href, stackFrame.line]);
  1384.     },
  1385.  
  1386.     getSourceLink: function(stackFrame)
  1387.     {
  1388.         var sourceLink = new SourceLink(stackFrame.href, stackFrame.line, "js");
  1389.         return sourceLink;
  1390.     },
  1391. });
  1392.  
  1393. // ************************************************************************************************
  1394.  
  1395. this.StackTrace = domplate(Firebug.Rep,
  1396. {
  1397.     tag:
  1398.         DIV({role : "group", 'aria-label' : $STR('aria.labels.stack trace')},
  1399.             FOR("frame", "$object.frames",
  1400.                 TAG(this.StackFrame.tag, {object: "$frame"})
  1401.             )
  1402.         ),
  1403.  
  1404.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1405.  
  1406.     className: "stackTrace",
  1407.  
  1408.     supportsObject: function(object)
  1409.     {
  1410.         return object instanceof StackTrace;
  1411.     }
  1412. });
  1413.  
  1414. // ************************************************************************************************
  1415.  
  1416. this.jsdStackFrame = domplate(Firebug.Rep,
  1417. {
  1418.     inspectable: false,
  1419.  
  1420.     className: "jsdIStactFrame",
  1421.  
  1422.     supportsObject: function(object)
  1423.     {
  1424.         return (object instanceof jsdIStackFrame);
  1425.     },
  1426.  
  1427.     getTitle: function(frame, context)
  1428.     {
  1429.         if (!frame.isValid) return "(invalid frame)"; // XXXjjb avoid frame.script == null
  1430.         return getFunctionName(frame.script, context);
  1431.     },
  1432.  
  1433.     getTooltip: function(frame, context)
  1434.     {
  1435.         if (!frame.isValid) return "(invalid frame; did Firebug suspend?)";  // XXXjjb avoid frame.script == null
  1436.         var sourceInfo = Firebug.SourceFile.getSourceFileAndLineByScript(context, frame.script, frame);
  1437.         if (sourceInfo)
  1438.             return $STRF("Line", [sourceInfo.sourceFile.href, sourceInfo.lineNo]);
  1439.         else
  1440.             return $STRF("Line", [frame.script.fileName, frame.line]);
  1441.     },
  1442.  
  1443.     getContextMenuItems: function(frame, target, context)
  1444.     {
  1445.         var fn = unwrapIValue(frame.script.functionObject);
  1446.         return FirebugReps.Func.getContextMenuItems(fn, target, context, frame.script);
  1447.     }
  1448. });
  1449.  
  1450. // ************************************************************************************************
  1451.  
  1452. this.ErrorMessage = domplate(Firebug.Rep,
  1453. {
  1454.     tag:
  1455.         OBJECTBOX({
  1456.                 $hasTwisty: "$object|hasStackTrace",
  1457.                 $hasBreakSwitch: "$object|hasBreakSwitch",
  1458.                 $breakForError: "$object|hasErrorBreak",
  1459.                 _repObject: "$object",
  1460.                 _stackTrace: "$object|getLastErrorStackTrace",
  1461.                 onclick: "$onToggleError"},
  1462.  
  1463.             DIV({"class": "errorTitle focusRow subLogRow", role : 'listitem'},
  1464.                 SPAN({"class": "errorDuplication"}, "$object.msgId|getDuplication"),
  1465.                 "$object.message|getMessage"
  1466.             ),
  1467.             DIV({"class": "errorTrace", role : 'presentation'}),
  1468.             DIV({"class": "errorSourceBox errorSource-$object|getSourceType focusRow subLogRow", role : "listitem"},
  1469.                 IMG({"class": "errorBreak a11yFocus", src:"blank.gif", role : 'checkbox', 'aria-checked':"$object|hasErrorBreak", title: "Break on this error"}),
  1470.                 A({"class": "errorSource a11yFocus"}, "$object|getLine"),
  1471.                 TAG(this.SourceLink.tag, {object: "$object|getSourceLink"})
  1472.             )
  1473.         ),
  1474.  
  1475.     getLastErrorStackTrace: function(error)
  1476.     {
  1477.         return error.trace;
  1478.     },
  1479.  
  1480.     hasStackTrace: function(error)
  1481.     {
  1482.         var url = error.href.toString();
  1483.         var fromCommandLine = (url.indexOf("XPCSafeJSObjectWrapper") != -1);
  1484.         return !fromCommandLine && error.trace;
  1485.     },
  1486.  
  1487.     hasBreakSwitch: function(error)
  1488.     {
  1489.         return error.href && error.lineNo > 0;
  1490.     },
  1491.  
  1492.     hasErrorBreak: function(error)
  1493.     {
  1494.         return fbs.hasErrorBreakpoint(normalizeURL(error.href), error.lineNo);
  1495.     },
  1496.  
  1497.     getMessage: function(message)
  1498.     {
  1499.         var re = /\[Exception... "(.*?)" nsresult:/;
  1500.         var m = re.exec(message);
  1501.         return m ? m[1] : message;
  1502.     },
  1503.  
  1504.     getDuplication: function(msgId)
  1505.     {
  1506.         return ""; // filled in later
  1507.     },
  1508.  
  1509.     getLine: function(error)
  1510.     {
  1511.         if (error.source)
  1512.             return cropMultipleLines(error.source, 80);
  1513.         if (error.category == "js" && error.href && error.href.indexOf("XPCSafeJSObjectWrapper") != -1)
  1514.             return "";
  1515.         var source = error.getSourceLine();
  1516.         if (source)
  1517.             return cropString(source, 80);
  1518.         return "";
  1519.     },
  1520.  
  1521.     getSourceLink: function(error)
  1522.     {
  1523.         var ext = error.category == "css" ? "css" : "js";
  1524.         return error.lineNo ? new SourceLink(error.href, error.lineNo, ext) : null;
  1525.     },
  1526.  
  1527.     getSourceType: function(error)
  1528.     {
  1529.         // Errors occurring inside of HTML event handlers look like "foo.html (line 1)"
  1530.         // so let's try to skip those
  1531.         if (error.source)
  1532.             return "syntax";
  1533.         else if (error.lineNo == 1 && getFileExtension(error.href) != "js")
  1534.             return "none";
  1535.         else if (error.category == "css")
  1536.             return "show";
  1537.         else if (!error.href || !error.lineNo)
  1538.             return "none";
  1539.         else
  1540.             return "show";
  1541.     },
  1542.  
  1543.     onToggleError: function(event)
  1544.     {
  1545.         var target = event.currentTarget;
  1546.         if (hasClass(event.target, "errorBreak"))
  1547.         {
  1548.             var panel = Firebug.getElementPanel(event.target);
  1549.             this.breakOnThisError(target.repObject, panel.context);
  1550.         }
  1551.         else if (hasClass(event.target, "errorSource"))
  1552.         {
  1553.             var panel = Firebug.getElementPanel(event.target);
  1554.             this.inspectObject(target.repObject, panel.context);
  1555.         }
  1556.         else if (hasClass(event.target, "errorTitle"))
  1557.         {
  1558.             var traceBox = target.childNodes[1];
  1559.             toggleClass(target, "opened");
  1560.             event.target.setAttribute('aria-expanded', hasClass(target, "opened"));
  1561.             if (hasClass(target, "opened"))
  1562.             {
  1563.                 if (target.stackTrace)
  1564.                     var node = FirebugReps.StackTrace.tag.append({object: target.stackTrace}, traceBox);
  1565.                 if (Firebug.A11yModel.enabled)
  1566.                 {
  1567.                     var panel = Firebug.getElementPanel(event.target);
  1568.                     dispatch([Firebug.A11yModel], "modifyLogRow", [panel , traceBox]);
  1569.                 }
  1570.             }
  1571.             else
  1572.                 clearNode(traceBox);
  1573.         }
  1574.     },
  1575.  
  1576.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1577.  
  1578.     copyError: function(error)
  1579.     {
  1580.         var message = [
  1581.             this.getMessage(error.message),
  1582.             error.href,
  1583.             "Line " +  error.lineNo
  1584.         ];
  1585.         copyToClipboard(message.join("\n"));
  1586.     },
  1587.  
  1588.     breakOnThisError: function(error, context)
  1589.     {
  1590.  
  1591.         var sourceFile = context.sourceFileMap[normalizeURL(error.href)];
  1592.         if (!sourceFile)
  1593.         {
  1594.             Firebug.Console.logFormatted(["reps.breakOnThisError has not source file for error.href: "+error.href, error], context, 'error', true);
  1595.             return;
  1596.         }
  1597.  
  1598.         if (this.hasErrorBreak(error))
  1599.             Firebug.Debugger.clearErrorBreakpoint(sourceFile, error.lineNo);
  1600.         else
  1601.             Firebug.Debugger.setErrorBreakpoint(sourceFile, error.lineNo);
  1602.     },
  1603.  
  1604.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1605.  
  1606.     className: "errorMessage",
  1607.     inspectable: false,
  1608.  
  1609.     supportsObject: function(object)
  1610.     {
  1611.         return object instanceof ErrorMessage;
  1612.     },
  1613.  
  1614.     inspectObject: function(error, context)
  1615.     {
  1616.         var sourceLink = this.getSourceLink(error);
  1617.         FirebugReps.SourceLink.inspectObject(sourceLink, context);
  1618.     },
  1619.  
  1620.     getContextMenuItems: function(error, target, context)
  1621.     {
  1622.         var breakOnThisError = this.hasErrorBreak(error);
  1623.  
  1624.         var items = [
  1625.             {label: "CopyError", command: bindFixed(this.copyError, this, error) }
  1626.         ];
  1627.  
  1628.         if (error.category == "css")
  1629.         {
  1630.             items.push(
  1631.                 "-",
  1632.                 {label: "BreakOnThisError", type: "checkbox", checked: breakOnThisError,
  1633.                  command: bindFixed(this.breakOnThisError, this, error) },
  1634.  
  1635.                 optionMenu("BreakOnAllErrors", "breakOnErrors")
  1636.             );
  1637.         }
  1638.  
  1639.         return items;
  1640.     }
  1641. });
  1642.  
  1643. // ************************************************************************************************
  1644.  
  1645. this.Assert = domplate(Firebug.Rep,
  1646. {
  1647.     tag:
  1648.         DIV(
  1649.             DIV({"class": "errorTitle"}),
  1650.             DIV({"class": "assertDescription"})
  1651.         ),
  1652.  
  1653.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1654.  
  1655.     className: "assert",
  1656.  
  1657.     inspectObject: function(error, context)
  1658.     {
  1659.         var sourceLink = this.getSourceLink(error);
  1660.         Firebug.chrome.select(sourceLink);
  1661.     },
  1662.  
  1663.     getContextMenuItems: function(error, target, context)
  1664.     {
  1665.         var breakOnThisError = this.hasErrorBreak(error);
  1666.  
  1667.         return [
  1668.             {label: "CopyError", command: bindFixed(this.copyError, this, error) },
  1669.             "-",
  1670.             {label: "BreakOnThisError", type: "checkbox", checked: breakOnThisError,
  1671.              command: bindFixed(this.breakOnThisError, this, error) },
  1672.             {label: "BreakOnAllErrors", type: "checkbox", checked: Firebug.breakOnErrors,
  1673.              command: bindFixed(this.breakOnAllErrors, this, error) }
  1674.         ];
  1675.     }
  1676. });
  1677.  
  1678. // ************************************************************************************************
  1679.  
  1680. this.SourceText = domplate(Firebug.Rep,
  1681. {
  1682.     tag:
  1683.         DIV(
  1684.             FOR("line", "$object|lineIterator",
  1685.                 DIV({"class": "sourceRow", role : "presentation"},
  1686.                     SPAN({"class": "sourceLine", role : "presentation"}, "$line.lineNo"),
  1687.                     SPAN({"class": "sourceRowText", role : "presentation"}, "$line.text")
  1688.                 )
  1689.             )
  1690.         ),
  1691.  
  1692.     lineIterator: function(sourceText)
  1693.     {
  1694.         var maxLineNoChars = (sourceText.lines.length + "").length;
  1695.         var list = [];
  1696.  
  1697.         for (var i = 0; i < sourceText.lines.length; ++i)
  1698.         {
  1699.             // Make sure all line numbers are the same width (with a fixed-width font)
  1700.             var lineNo = (i+1) + "";
  1701.             while (lineNo.length < maxLineNoChars)
  1702.                 lineNo = " " + lineNo;
  1703.  
  1704.             list.push({lineNo: lineNo, text: sourceText.lines[i]});
  1705.         }
  1706.  
  1707.         return list;
  1708.     },
  1709.  
  1710.     getHTML: function(sourceText)
  1711.     {
  1712.         return getSourceLineRange(sourceText, 1, sourceText.lines.length);
  1713.     }
  1714. });
  1715.  
  1716. //************************************************************************************************
  1717.  
  1718. this.nsIDOMHistory = domplate(Firebug.Rep,
  1719. {
  1720.     tag:OBJECTBOX({onclick: "$showHistory"},
  1721.             OBJECTLINK("$object|summarizeHistory")
  1722.         ),
  1723.  
  1724.     className: "nsIDOMHistory",
  1725.  
  1726.     summarizeHistory: function(history)
  1727.     {
  1728.         try
  1729.         {
  1730.             var items = history.length;
  1731.             return items + " history entries";
  1732.         }
  1733.         catch(exc)
  1734.         {
  1735.             return "object does not support history (nsIDOMHistory)";
  1736.         }
  1737.     },
  1738.  
  1739.     showHistory: function(history)
  1740.     {
  1741.         try
  1742.         {
  1743.             var items = history.length;  // if this throws, then unsupported
  1744.             Firebug.chrome.select(history);
  1745.         }
  1746.         catch (exc)
  1747.         {
  1748.         }
  1749.     },
  1750.  
  1751.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1752.  
  1753.     supportsObject: function(object, type)
  1754.     {
  1755.         return (object instanceof Ci.nsIDOMHistory);
  1756.     }
  1757. });
  1758.  
  1759. // ************************************************************************************************
  1760.  
  1761. this.ApplicationCache = domplate(Firebug.Rep,
  1762. {
  1763.     tag:OBJECTBOX({onclick: "$showApplicationCache"},
  1764.             OBJECTLINK("$object|summarizeCache")
  1765.         ),
  1766.  
  1767.     summarizeCache: function(applicationCache)
  1768.     {
  1769.         try
  1770.         {
  1771.             return applicationCache.length + " items in offline cache";
  1772.         }
  1773.         catch(exc)
  1774.         {
  1775.             return "https://bugzilla.mozilla.org/show_bug.cgi?id=422264";
  1776.         }
  1777.     },
  1778.  
  1779.     showApplicationCache: function(event)
  1780.     {
  1781.         openNewTab("https://bugzilla.mozilla.org/show_bug.cgi?id=422264");
  1782.     },
  1783.  
  1784.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1785.  
  1786.     className: "applicationCache",
  1787.  
  1788.     supportsObject: function(object, type)
  1789.     {
  1790.         if (Ci.nsIDOMOfflineResourceList)
  1791.             return (object instanceof Ci.nsIDOMOfflineResourceList);
  1792.     }
  1793.  
  1794. });
  1795.  
  1796. this.Storage = domplate(Firebug.Rep,
  1797. {
  1798.     tag: OBJECTBOX({onclick: "$show"}, OBJECTLINK("$object|summarize")),
  1799.  
  1800.     summarize: function(storage)
  1801.     {
  1802.         return storage.length +" items in Storage";
  1803.     },
  1804.     show: function(storage)
  1805.     {
  1806.         openNewTab("http://dev.w3.org/html5/webstorage/#storage-0");
  1807.     },
  1808.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1809.  
  1810.     className: "Storage",
  1811.  
  1812.     supportsObject: function(object, type)
  1813.     {
  1814.         return (object instanceof Storage);
  1815.     }
  1816.  
  1817. });
  1818.  
  1819. // ************************************************************************************************
  1820.  
  1821. Firebug.registerRep(
  1822.     this.nsIDOMHistory, // make this early to avoid exceptions
  1823.     this.Undefined,
  1824.     this.Null,
  1825.     this.Number,
  1826.     this.String,
  1827.     this.Window,
  1828.     this.ApplicationCache, // must come before Arr (array) else exceptions.
  1829.     this.ErrorMessage,
  1830.     this.Element,
  1831.     this.TextNode,
  1832.     this.Document,
  1833.     this.StyleSheet,
  1834.     this.Event,
  1835.     this.SourceLink,
  1836.     this.SourceFile,
  1837.     this.StackTrace,
  1838.     this.StackFrame,
  1839.     this.jsdStackFrame,
  1840.     this.jsdScript,
  1841.     this.NetFile,
  1842.     this.Property,
  1843.     this.Except,
  1844.     this.XML,
  1845.     this.Arr
  1846. );
  1847.  
  1848. Firebug.setDefaultReps(this.Func, this.Obj);
  1849.  
  1850. }});
  1851.  
  1852. // ************************************************************************************************
  1853. /*
  1854.  * The following is http://developer.yahoo.com/yui/license.txt and applies to only code labeled "Yahoo BSD Source"
  1855.  * in only this file reps.js.  John J. Barton June 2007.
  1856.  *
  1857. Software License Agreement (BSD License)
  1858.  
  1859. Copyright (c) 2006, Yahoo! Inc.
  1860. All rights reserved.
  1861.  
  1862. Redistribution and use of this software in source and binary forms, with or without modification, are
  1863. permitted provided that the following conditions are met:
  1864.  
  1865. * Redistributions of source code must retain the above
  1866.   copyright notice, this list of conditions and the
  1867.   following disclaimer.
  1868.  
  1869. * Redistributions in binary form must reproduce the above
  1870.   copyright notice, this list of conditions and the
  1871.   following disclaimer in the documentation and/or other
  1872.   materials provided with the distribution.
  1873.  
  1874. * Neither the name of Yahoo! Inc. nor the names of its
  1875.   contributors may be used to endorse or promote products
  1876.   derived from this software without specific prior
  1877.   written permission of Yahoo! Inc.
  1878.  
  1879. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
  1880. WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  1881. PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  1882. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  1883. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  1884. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  1885. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  1886. ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  1887.  * /
  1888.  */
  1889.